package org.nicocube.airain.app.server;

import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

import javax.jdo.PersistenceManager;
import javax.jdo.Query;

import org.nicocube.airain.app.client.GCService;
import org.nicocube.airain.app.client.domain.GameCharacter;
import org.nicocube.airain.app.client.exception.GCCreateException;
import org.nicocube.airain.app.client.exception.GCMaxNumberCreateException;
import org.nicocube.airain.app.client.exception.GCNameDuplicateCreateException;
import org.nicocube.airain.app.server.domain.GameCharacterStorable;

import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;

public class GCServiceImpl extends RemoteServiceServlet implements GCService {
	private static final Logger log = Logger.getLogger(GCServiceImpl.class.getName());
	
	private static final long serialVersionUID = 1L;

	public List<GameCharacter> getList() {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		try {
	        UserService userService = UserServiceFactory.getUserService();
			User user = userService.getCurrentUser();
			
		    Query query = pm.newQuery(GameCharacterStorable.class,"owner == ownerParam");
		    query.setOrdering("birthDate desc");
		    query.declareParameters("com.google.appengine.api.users.User ownerParam");

		    @SuppressWarnings("unchecked")
			List<GameCharacterStorable> queryResult = (List<GameCharacterStorable>) query.execute(user);
		    
		    List<GameCharacter> result = new ArrayList<GameCharacter>(queryResult.size());
			for (GameCharacterStorable gcSto: queryResult) {
				GameCharacter e =  new GameCharacter(
						gcSto.getOrder().longValue(),
						gcSto.getName(),
						gcSto.getGender(),
						gcSto.getBirthDate()
				);
				
				result.add(e);
			}
			
			return result ;
		} finally {
			pm.close();
		}
	}
	
	@Override
	public GameCharacter create(GameCharacter gc) throws GCCreateException {
		log.info("create("+gc.getName()+","+gc.getGender()+")");
		PersistenceManager pm = PMF.get().getPersistenceManager();
		GameCharacter result;
		try {
	        UserService userService = UserServiceFactory.getUserService();
			User user = userService.getCurrentUser();

			Query query0 = pm.newQuery(GameCharacterStorable.class);
		    query0.setResult("count(owner)");
		    query0.setFilter("owner == ownerParam");
		    query0.declareParameters("com.google.appengine.api.users.User ownerParam");

		    Integer res0 = (Integer) query0.execute(user);

		    if (res0 >= 3) {
		    	throw new GCMaxNumberCreateException();
		    }
			
		    Query query1 = pm.newQuery(GameCharacterStorable.class);
		    query1.setResult("count(*)");
		    query1.setFilter("name == newName && owner == ownerParam");
		    query1.declareParameters("java.lang.String newName,com.google.appengine.api.users.User ownerParam");

		    Integer res1 = (Integer) query1.execute(gc.getName(),user);
			
		    if (res1 > 0) {
		    	log.warning("res1="+res1);
		    	throw new GCNameDuplicateCreateException();
		    }
		    
			GameCharacterStorable gcSto = new GameCharacterStorable(
					gc.getName(),
					gc.getGender(),
					user
			);
			
			pm.makePersistent(gcSto);
			
			result =  new GameCharacter(
					gcSto.getOrder().longValue(),
					gcSto.getName(),
					gcSto.getGender(),
					gcSto.getBirthDate()
			);
			
		} finally {
			pm.close();
		}
		return result;
	}

	@Override
	public boolean delete(GameCharacter gc) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		boolean done = false;
		try {
	        UserService userService = UserServiceFactory.getUserService();
			User user = userService.getCurrentUser();

			log.info("user="+user);
			
			GameCharacterStorable gcSto = pm.getObjectById(GameCharacterStorable.class, gc.getOrder());
			
			log.info("gcSto.getOwner()="+gcSto.getOwner());
			
			if (user.equals(gcSto.getOwner())) {
				pm.deletePersistent(gcSto);
				done  = true;
			}			
		} finally {
			pm.close();
		}
		return done;
	}

}
